use {
    super::client::Address,
    serde::Serializer,
    serde_derive::Serialize,
};

/// Parameters used to get series images with
/// [`Client::series_images_query`](../client/struct.Client.html#method.series_images_query).
#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetBlockByNumParams {
    num: u64,
    visible: bool,
}

impl GetBlockByNumParams {
    pub fn new(num: u64) -> GetBlockByNumParams {
        GetBlockByNumParams { num, visible: true }
    }
}

#[derive(Debug, Default, Serialize)]
pub struct GetNowBlockParams {
    visible: bool,
}

impl GetNowBlockParams {
    pub fn new() -> GetNowBlockParams {
        GetNowBlockParams { visible: false }
    }
}

#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetBlockByRangeParams {
    start_num: u64,
    end_num: u64,
}

impl GetBlockByRangeParams {
    pub fn new(start_num: u64, end_num: u64) -> GetBlockByRangeParams {
        GetBlockByRangeParams { start_num, end_num }
    }
}

#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetBlockByIdParams {
    #[serde(rename = "value")]
    id: String,
}

impl GetBlockByIdParams {
    pub fn new(id: String) -> GetBlockByIdParams {
        GetBlockByIdParams { id }
    }
}

#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetAccountParams {
    #[serde(rename = "address")]
    address: String,
    // true if address is in base58...
    visible: bool,
}

impl GetAccountParams {
    pub fn new(address: Address) -> GetAccountParams {
        let (address, visible) = match address {
            Address::Base58(addr) => (addr, true),
            Address::Hex(addr) => (addr, false),
        };

        GetAccountParams { address, visible }
    }
}

#[derive(Debug, Default)]
pub struct EmptyBody {}
impl serde::Serialize for EmptyBody {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: Serializer,
    {
        serializer.serialize_str("")
    }
}

#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct GetContractParams {
    #[serde(rename = "value")]
    address: String,
}

impl GetContractParams {
    pub fn new(address: Address) -> GetContractParams {
        let address = match address {
            Address::Base58(addr) => addr,
            Address::Hex(addr) => addr,
        };

        GetContractParams { address }
    }
}

#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CreateTransactionParams {
    #[serde(rename = "owner_address")]
    owner_address: String,
    #[serde(rename = "to_address")]
    to_address: String,
    #[serde(rename = "amount")]
    amount: u64,
    // true if address is in base58...
    visible: bool,
}

impl CreateTransactionParams {
    pub fn new(from_address: Address, to_address: Address, amount: u64) -> CreateTransactionParams {
        let (owner_address, _) = match from_address {
            Address::Base58(addr) => (addr, true),
            Address::Hex(addr) => (addr, false),
        };
        let (to_address, visible) = match to_address {
            Address::Base58(addr) => (addr, true),
            Address::Hex(addr) => (addr, false),
        };

        CreateTransactionParams {
            owner_address,
            to_address,
            amount,
            visible,
        }
    }
}

#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct BroadcasthexParams {
    #[serde(rename = "transaction")]
    transaction: String,
}

impl BroadcasthexParams {
    pub fn new(transaction: String) -> BroadcasthexParams {
        BroadcasthexParams { transaction }
    }
}

#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TriggerconstantcontractParams {
    #[serde(rename = "contract_address")]
    contract_address: String,
    #[serde(rename = "function_selector")]
    function_selector: String,
    #[serde(rename = "owner_address")]
    owner_address: String,
    #[serde(rename = "parameter")]
    parameter: String,
    // true if address is in base58...
    visible: bool,
}

impl TriggerconstantcontractParams {
    pub fn new(
        contract_address: String,
        function_selector: String,
        owner_address: String,
        parameter: String,
    ) -> TriggerconstantcontractParams {
        TriggerconstantcontractParams {
            contract_address,
            function_selector,
            owner_address,
            parameter,
            visible: true,
        }
    }
}

#[derive(Debug, Default, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct TriggerSmartContractParams {
    #[serde(rename = "contract_address")]
    contract_address: String,
    #[serde(rename = "function_selector")]
    function_selector: String,
    #[serde(rename = "owner_address")]
    owner_address: String,
    #[serde(rename = "parameter")]
    parameter: String,
    #[serde(rename = "fee_limit")]
    fee_limit: u32,
    #[serde(rename = "call_value")]
    call_value: u128,
    // true if address is in base58...
    visible: bool,
}

impl TriggerSmartContractParams {
    pub fn new(
        contract_address: String,
        function_selector: String,
        owner_address: String,
        parameter: String,
        fee_limit: u32,
        call_value: u128,
    ) -> TriggerSmartContractParams {
        TriggerSmartContractParams {
            contract_address,
            function_selector,
            owner_address,
            parameter,
            fee_limit,
            call_value,
            visible: true,
        }
    }
}
